use nalgebra::{Point3, Vector2, Vector3};
use obj::{load_obj, Obj, TexturedVertex};
use russimp::property::PropertyStore;
use russimp::scene::Scene;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use QcRender::geometry::Vertex;
use QcRender::resources::MeshFile;
use serde::{Deserialize, Serialize};

#[cxx::bridge(namespace = "QcExport")]
mod ffi {
    extern "Rust" {

        pub fn create_mesh_from_obj(url: &str);

        pub fn create_mesh_from_gltf(url: &str);
    }
}

pub fn create_mesh_from_obj(url: &str) {
    println!("url:{}", url);

    let path = Path::new(url);
    let input = BufReader::new(File::open(path).expect("找不到文件"));
    let obj: Obj<TexturedVertex, u16> = load_obj(input).unwrap();

    let indices: Vec<u16> = obj.indices.clone();
    let vertices = obj
        .vertices
        .iter()
        .map(|v| {
            Vertex::new(
                v.position.into(),
                Vector2::new(v.texture[0], v.texture[1]),
                v.normal.into(),
            )
        })
        .collect::<Vec<Vertex>>();
    let mesh_file = MeshFile::new(vertices, indices);

    let mesh = ron::to_string(&mesh_file).unwrap();

    let mut path = path.to_path_buf();
    path.set_extension("mesh");

    println!("path:{:?}", path);
    std::fs::write(path, mesh).unwrap();
}

#[test]
fn export_gltf() {
    create_mesh_from_gltf("D:/Projects/rust/quincy_rubbish/cube.gltf");
}

pub fn create_mesh_from_gltf(url: &str) {
    let scene = Scene::from_file(url, vec![]).unwrap();

    let mesh = scene.meshes.first().unwrap();
    let mut indices: Vec<u16> = vec![];

    for face in &mesh.faces {
        println!("{:?}", face);
        indices.push(face.0[0] as _);
        indices.push(face.0[1] as _);
        indices.push(face.0[2] as _);
    }
    let mut vertices = vec![];

    let positions = &mesh.vertices;
    let uvs = mesh.texture_coords[0].as_ref().unwrap();
    let normals = &mesh.normals;
    let tangents = &mesh.tangents;
    let bitangents = &mesh.bitangents;

    for i in 0..positions.len() {
        let position = positions[i];
        let position = Point3::new(position.x, position.y, position.z);

        let uv = uvs[i];
        let uv = Vector2::new(uv.x, uv.y);
        let normal = normals[i];
        let normal = Vector3::new(normal.x, normal.y, normal.z);
        let tangent = tangents[i];
        let tangent = Vector3::new(tangent.x, tangent.y, tangent.z);
        let bitangent = bitangents[i];
        let bitangent = Vector3::new(bitangent.x, bitangent.y, bitangent.z);
        vertices.push(
            Vertex::new(position, uv, normal)
                .with_tangent(tangent)
                .with_bitangent(bitangent),
        )
    }

    println!("indices {:?}", indices);

    println!("vertices {:?}", vertices);

    let mesh_file = MeshFile::new(vertices, indices);

    let mesh = ron::to_string(&mesh_file).unwrap();
    let path = Path::new(url);
    let mut path = path.to_path_buf();
    path.set_extension("mesh");

    println!("path:{:?}", path);
    std::fs::write(path, mesh).unwrap();
}

#[derive(Debug, Serialize, Deserialize, Default)]
struct OldVertex {
    position: Point3<f32>,
    texCoords: Vector2<f32>,
    normals: Vector3<f32>,
}

#[derive(Debug, Serialize, Deserialize, Default)]
struct OldMesh {
    pub vertices: Vec<OldVertex>,
    pub indices: Vec<u16>,
}

#[test]
fn update_mesh() {
    let path = Path::new("D:/Projects/rust/Quincy/crates/QcRender/assets/model/rotate.mesh");

    let file = std::fs::read_to_string(path).unwrap();

    let mesh: OldMesh = ron::from_str(&file).unwrap();

    let vertices = mesh
        .vertices
        .iter()
        .map(|mesh| Vertex::new(mesh.position, mesh.texCoords, mesh.normals))
        .collect();

    let indices = mesh.indices;
    let mesh_file = MeshFile::new(vertices, indices);
    let mesh = ron::to_string(&mesh_file).unwrap();

    std::fs::write(path, mesh).unwrap();
}
